package com.luo.chengrui.module.sa.service.org;

import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import com.luo.chengrui.framework.sadatapermission.core.annotation.SaDataPermission;
import com.luo.chengrui.module.sa.api.org.dto.OrgRespDTO;
import com.luo.chengrui.module.sa.constant.SaConstants;
import com.luo.chengrui.module.sa.controller.admin.org.vo.*;
import com.luo.chengrui.module.sa.convert.org.OrgConvert;
import com.luo.chengrui.module.sa.dal.dataobject.org.OrgDO;
import com.luo.chengrui.module.sa.dal.dataobject.person.PersonDO;
import com.luo.chengrui.module.sa.dal.mysql.org.OrgMapper;
import com.luo.chengrui.module.sa.dal.mysql.person.PersonMapper;
import com.luo.chengrui.module.sa.dal.redis.RedisKeyConstants;
import com.luo.chengrui.module.sa.enums.GlobalStatusEnum;
import com.luo.chengrui.module.sa.enums.OrgKindEnum;
import com.luo.chengrui.module.sa.enums.YesOrNoEnum;
import com.luo.chengrui.module.sa.service.person.PersonService;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.luo.chengrui.module.sa.enums.ErrorCodeConstants.ORG_IS_DISABLED;
import static com.luo.chengrui.module.sa.enums.ErrorCodeConstants.ORG_NOT_EXISTS;

/**
 * 组织机构管理 Service 实现类
 *
 * @author 诚睿
 */
@Service
@Validated
public class OrgServiceImpl implements OrgService {


    @Resource
    private OrgMapper orgMapper;

    @Resource
    private PersonMapper personMapper;
    @Resource
    private OrgAndPersonSyncService orgAndPersonSyncService;

    public OrgServiceImpl getSelf() {
        return SpringUtil.getBean(getClass());
    }

    public PersonService getPersonService() {
        return SpringUtil.getBean(PersonService.class);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createOrg(OrgCreateReqVO createReqVO) {
        // 插入
        OrgDO org = OrgConvert.INSTANCE.convert(createReqVO);
        org.setVersion(System.currentTimeMillis());
        // 如果是中心
        if (Objects.equals(SaConstants.COMMON_STATUS_YES, org.getIsCenter())) {
            org.setOrgKindId(OrgKindEnum.Center.getCode());
        }
        orgMapper.insert(org);

        OrgDO parent = this.getOrg(createReqVO.getParentId());
        if (parent != null) {
            org.setFullId(parent.getFullId() + SaConstants.FULL_PATH_SEPARATE + org.getId());
            org.setFullOrgKindId(parent.getFullOrgKindId() + SaConstants.FULL_PATH_SEPARATE + org.getOrgKindId());
            org.setFullCode(parent.getFullCode() + SaConstants.FULL_PATH_SEPARATE + org.getCode());
            org.setFullName(parent.getFullName() + SaConstants.FULL_PATH_SEPARATE + org.getName());
        } else {
            org.setFullId(SaConstants.FULL_PATH_SEPARATE + org.getId());
            org.setFullOrgKindId(SaConstants.FULL_PATH_SEPARATE + org.getOrgKindId());
            org.setFullCode(SaConstants.FULL_PATH_SEPARATE + org.getCode());
            org.setFullName(SaConstants.FULL_PATH_SEPARATE + org.getName());
        }

        OrgKindEnum orgKind = OrgKindEnum.getByCode(createReqVO.getOrgKindId());
        switch (orgKind) {
            case Org:
                // 机构
                org.setOrgId(org.getId());
                org.setOrgCode(org.getCode());
                org.setOrgName(org.getName());
                break;
            case Center:
                // 中心
                org.setOrgId(parent.getOrgId());
                org.setOrgCode(parent.getOrgCode());
                org.setOrgName(parent.getOrgName());

                org.setCenterName(org.getName());
                org.setCenterCode(org.getCode());
                org.setCenterId(org.getId());
                break;
            case Dept:
                // 部门
                org.setOrgId(parent.getOrgId());
                org.setOrgCode(parent.getOrgCode());
                org.setOrgName(parent.getOrgName());
                org.setCenterName(parent.getCenterName());
                org.setCenterCode(parent.getCenterCode());
                org.setCenterId(parent.getCenterId());

                org.setDeptName(org.getName());
                org.setDeptCode(org.getCode());
                org.setDeptId(org.getId());
                break;
            case Position:
                // 岗位
                org.setOrgId(parent.getOrgId());
                org.setOrgCode(parent.getOrgCode());
                org.setOrgName(parent.getOrgName());
                org.setCenterName(parent.getCenterName());
                org.setCenterCode(parent.getCenterCode());
                org.setCenterId(parent.getCenterId());
                org.setDeptName(parent.getDeptName());
                org.setDeptCode(parent.getDeptCode());
                org.setDeptId(parent.getDeptId());

                org.setPositionName(org.getName());
                org.setPositionCode(org.getCode());
                org.setPositionId(org.getId());
                break;
            case Psm:
                // 人员
                org.setOrgId(parent.getOrgId());
                org.setOrgCode(parent.getOrgCode());
                org.setOrgName(parent.getOrgName());
                org.setCenterName(parent.getCenterName());
                org.setCenterCode(parent.getCenterCode());
                org.setCenterId(parent.getCenterId());
                org.setDeptName(parent.getDeptName());
                org.setDeptCode(parent.getDeptCode());
                org.setDeptId(parent.getDeptId());
                org.setPositionName(parent.getPositionName());
                org.setPositionCode(parent.getPositionCode());
                org.setPositionId(parent.getPositionId());
                org.setPersonMemberName(org.getName());
                org.setPersonMemberCode(org.getCode());
                org.setPersonMemberId(org.getId());
                break;
        }

        orgMapper.updateById(org);

        //实时同步至系统部门表
        orgAndPersonSyncService.orgSync(org);
        return org.getOrgId();
    }

    @Override
    public void batchCreatePsm(List<OrgCreateReqVO> createReqVO) {
        if (!Objects.isNull(createReqVO)) {
            for (OrgCreateReqVO vo : createReqVO) {
                vo.setId(vo.getPersonId() + "@" + vo.getParentId());
                if (orgMapper.selectById(vo.getId()) == null) {
                    getSelf().createOrg(vo);
                    getPersonService().repairMainOrgId(vo.getPersonId(), vo.getParentId());
                }
            }
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateOrg(OrgUpdateReqVO updateReqVO) {
        // 校验存在
        validateOrgExists(updateReqVO.getId());
        // 更新
        OrgDO updateObj = OrgConvert.INSTANCE.convert(updateReqVO);
        orgMapper.updateById(updateObj);
        OrgDO updateDO = orgMapper.selectById(updateReqVO.getId());
        orgAndPersonSyncService.orgSync(updateDO);
    }

    @Override
    public void batchUpdate(List<OrgDO> updateOrgList) {
        orgMapper.updateBatch(updateOrgList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteOrg(String id) {
        // 校验存在
        OrgDO orgDO = orgMapper.selectById(id);
        if (orgDO == null) {
            throw exception(ORG_NOT_EXISTS);
        }
        // 删除
        orgMapper.deleteById(id);

        if (OrgKindEnum.Psm.getCode().equals(orgDO.getOrgKindId())) {
            //岗位数据主键有固定规则，需做物理删除，否则后续添加时会出现主键重复，无法添加的问题。
            orgMapper.deletePsmById(id);
        }

        if (!Objects.isNull(orgDO.getSystemId())) {
            orgAndPersonSyncService.deleteOrg(orgDO.getSystemId());
        }
    }

    private void validateOrgExists(String id) {
        if (orgMapper.selectById(id) == null) {
            throw exception(ORG_NOT_EXISTS);
        }
    }

    @Override
    public OrgDO getOrg(String id) {
        return orgMapper.selectById(id);
    }

    @Override
    @SaDataPermission(permissinCode = "orgTreeManageType", likeTargetColumn = "full_id")
    public List<OrgDO> getOrgList(Collection<String> ids) {
        return orgMapper.selectBatchIds(ids);
    }

    @Override
    @SaDataPermission(name = "getOrgPage", permissinCode = "orgTreeManageType", likeTargetColumn = "full_id")
    public PageResult<OrgDO> getOrgPage(OrgPageReqVO pageReqVO) {
        return orgMapper.selectPage(pageReqVO);
    }

    @Override
    @SaDataPermission(name = "getOrgList", permissinCode = "orgTreeManageType", likeTargetColumn = "full_id")
    public List<OrgDO> getOrgList(OrgExportReqVO exportReqVO) {
        return orgMapper.selectList(exportReqVO);
    }

    @Override
    public List<OrgDO> getPsmListBySystemUserId(Long systemUserId) {
        return orgMapper.selectPsmList(systemUserId);
    }

    @Override
    public List<String> getOrgFullIdListBySystemUserId(Long userId, OrgKindEnum orgKindEnum) {
        List<OrgDO> orgList = getSelf().getOrgListByUserId(userId);
        List<OrgDO> filterList = orgList.stream().filter(org -> Objects.equals(orgKindEnum.getCode(), org.getOrgKindId())).collect(Collectors.toList());
        return filterList.stream().map(OrgDO::getFullId).collect(Collectors.toList());
    }

    @Cacheable(value = RedisKeyConstants.SA_USER_ORG_LIST, key = "#systemUserId")
    public List<OrgDO> getOrgListByUserId(Long systemUserId) {
        return orgMapper.getOrgListByUserId(systemUserId);
    }

    @Override
    public List<OrgDO> getPsmListById(String personId) {
        OrgExportReqVO exportReqVO = new OrgExportReqVO();
        exportReqVO.setPersonId(personId);
        return orgMapper.selectList(exportReqVO);
    }

    @Override
    @SaDataPermission(permissinCode = "orgTreeManageType", likeTargetColumn = "full_id")
    public List<OrgDO> getChildrenBy(String id) {
        OrgExportReqVO exportReqVO = new OrgExportReqVO();
        exportReqVO.setParentId(id);
        if (StrUtil.isBlank(id)) {
            OrgDO rootOrg = new OrgDO();
            rootOrg.setName("组织机构");
            rootOrg.setId(ORG_ROOT_ID);
            rootOrg.setCode(OrgKindEnum.Root.getCode());
            rootOrg.setOrgKindId(OrgKindEnum.Root.getCode());
            List<OrgDO> rootOrgList = new ArrayList<>();
            rootOrgList.add(rootOrg);
            return (rootOrgList);
        }
        return orgMapper.selectList(exportReqVO);
    }

    @Override
    @SaDataPermission(name = "orgManagePermi", likeTargetColumn = "full_id", permissinCode = "#{permissionSubCode}")
    public List<OrgDO> getOrgAllList(OrgPageReqVO reqVo, String permissionSubCode) {
        reqVo.setStatus(Objects.isNull(reqVo.getStatus()) ? GlobalStatusEnum.ENABLED.getId() : reqVo.getStatus());
        reqVo.setIsVirtual(Objects.isNull(reqVo.getIsVirtual()) ? YesOrNoEnum.NO.getId() : reqVo.getIsVirtual());
        return orgMapper.selectAllList(reqVo);
    }

    @Override
    public List<OrgDO> getPsmListByFullIds(List<String> personFullIds) {
        return orgMapper.selectPsmListByFullIds(personFullIds);
    }

    @Override
    public List<OrgRespDTO> getAllPersonMemberListByOrgId(String orgId) {
        OrgDO org = this.getOrg(orgId);
        if (org == null) {
            throw exception(ORG_NOT_EXISTS);
        }
        if (Objects.equals(org.getStatus(), GlobalStatusEnum.DISABLED.getId())) {
            throw exception(ORG_IS_DISABLED);
        }
        OrgExportReqVO params = new OrgExportReqVO();
        params.setFullId(org.getFullId());
        params.setStatus(GlobalStatusEnum.ENABLED.getId());
        params.setOrgKindId(OrgKindEnum.Psm.getCode());
        List<OrgDO> list = this.getOrgList(params);
        if (list != null && list.size() > 0) {
            return OrgConvert.INSTANCE.convertList3(list);
        }
        return null;
    }

    @Override
    public void syncOrg(String id) {
        OrgDO orgDO = orgMapper.selectById(id);
        if (Objects.equals(OrgKindEnum.Psm.getCode(), orgDO.getOrgKindId())) {
            PersonDO personDO = personMapper.selectById(orgDO.getPersonId());
            orgAndPersonSyncService.personSync(personDO);
        } else {
            orgAndPersonSyncService.orgSync(orgDO);
        }
    }
}
